package com.bagus.mediapipefacedetection.module.base;

import android.hardware.Camera;
import android.view.SurfaceView;

import androidx.camera.core.ImageCapture;

import com.bagus.mediapipefacedetection.CameraXPreviewHelper;
import com.bagus.mediapipefacedetection.camera.CameraManager;
import com.bagus.mediapipefacedetection.manager.FpsManager;
import com.bagus.mediapipefacedetection.utils.ICamera;
import com.google.mediapipe.components.CameraHelper;
import com.google.mediapipe.components.ExternalTextureConverter;
import com.google.mediapipe.components.FrameProcessor;
import com.google.mediapipe.formats.proto.LandmarkProto;
import com.google.mediapipe.framework.AndroidAssetUtil;
import com.google.mediapipe.framework.Packet;
import com.google.mediapipe.framework.PacketCallback;
import com.google.mediapipe.framework.PacketGetter;
import com.google.mediapipe.glutil.EglManager;
import com.google.protobuf.InvalidProtocolBufferException;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;

public class BasePresenter<V extends BaseView, M extends BaseModel> {
    private static final String TAG = "BasePresenter";
    private V mView;
    private M mModel;
    protected ICamera mICamera;
    protected CameraManager mCameraManager;
    protected BlockingQueue<byte[]> mFrameDataQueue;

    private static final String FOCAL_LENGTH_STREAM_NAME = "focal_length_pixel";
    private static final String OUTPUT_LANDMARKS_STREAM_NAME = "face_landmarks_with_iris";
    private static final String BINARY_GRAPH_NAME = "iris_tracking_gpu.binarypb";
    private static final String INPUT_VIDEO_STREAM_NAME = "input_video";
    private static final String OUTPUT_VIDEO_STREAM_NAME = "output_video";
    private static  CameraHelper.CameraFacing CAMERA_FACING = CameraHelper.CameraFacing.FRONT;
    private static final boolean FLIP_FRAMES_VERTICALLY = true;
    private EglManager eglManager;
    private FrameProcessor frameProcessor;
    private ExternalTextureConverter externalTextureConverter;
    private CameraXPreviewHelper cameraXPreviewHelper;
    private ImageCapture.OnImageSavedCallback imageSavedCallback;
    private ImageCapture.Builder imageCaptureBuilder;
    private boolean landmarksExist;
    private boolean haveSidePackets = false;

    public void init() {
        mFrameDataQueue = new LinkedBlockingDeque<>(1);
        FpsManager.getInstance().init();

//        imageCaptureBuilder = new ImageCapture.Builder();
//
//        //Creating Image Saved Callback
//        generateImageSavedCallback();
//
//        setupPreviewDisplayView();
//
//        //Initializing Asset Manager
//        AndroidAssetUtil.initializeNativeAssetManager(this);
//
//        //Setting up Frame Processor
//        eglManager = new EglManager(null);
//        frameProcessor = new FrameProcessor(this, eglManager.getNativeContext(), BINARY_GRAPH_NAME, INPUT_VIDEO_STREAM_NAME, OUTPUT_VIDEO_STREAM_NAME);
//        frameProcessor.getVideoSurfaceOutput().setFlipY(FLIP_FRAMES_VERTICALLY);
//
//        //Adding the Landmark Packet Callback
//        addingLandmarkPacketCallback();
    }

    private void addingLandmarkPacketCallback() {
        frameProcessor.addPacketCallback(OUTPUT_LANDMARKS_STREAM_NAME,
                new PacketCallback() {
                    @Override
                    public void process(Packet packet) {
                        byte[] rawLandmarks = PacketGetter.getProtoBytes(packet);
                        try {
                            //Converting the Landmarks from their Raw Form
//                            currentLandmarks = LandmarkProto.NormalizedLandmarkList.parseFrom(rawLandmarks);
//
//                            //检测人脸图片
//                            getPresenter().doDetect2(currentLandmarks.getLandmarkList(),surfaceView.getWidth(),surfaceView.getHeight());
//                            //Updating the state of the landmarksExist Variable
//                            if (currentLandmarks == null) landmarksExist = false;
//                            else landmarksExist = true;

                        } catch (Exception e) {
                        }
                    }
                }
        );
    }

    public boolean openCamera() {
        try {
            if (mICamera == null){
                this.mICamera = new ICamera();
            }
//            ILogPrint.logw(TAG, "openCamera 1...");
            if (mICamera != null) {
                int cameraId = 1;
                if (!ICamera.hasFrontFacingCamera()) {
                    cameraId = 0;
                }
//                ILogPrint.logw(TAG, "openCamera 2...");
                Camera mCamera = mICamera.openCamera(getView().getActivity(), cameraId);
//                ILogPrint.logw(TAG, "openCamera 3...");
                return mCamera != null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public void closeCamera() {
        try {
            if (mICamera != null) {
//                ILogPrint.logw(TAG, "closeCamera...");
                mICamera.closeCamera();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void switchCamera() {
        try {
            if (mICamera != null) {
                mICamera.switchCamera(getView().getActivity());
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    public int getCameraHeight() {
        if (mICamera != null) {
            return mICamera.cameraHeight;
        }
        return 0;
    }

    public int getCameraWidth() {
        if (mICamera != null) {
            return mICamera.cameraWidth;
        }
        return 0;
    }

    public boolean attach(final V view) {
        mView = (V)Proxy.newProxyInstance(view.getClass().getClassLoader(), view.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (mView == null) {
                    return null;
                }
                return method.invoke(view, args);
            }
        });
        Type[] params = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
        try {
            mModel = (M) ((Class) params[1]).newInstance();
            return true;
        } catch (InstantiationException e) {
            e.printStackTrace();
            return false;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return false;
        }catch (Throwable t){
            return false;
        }
    }

    public void detach() {
        mView = null;
        mModel = null;
    }

    public V getView() {
        return mView;
    }

    public void setmView(V mView) {
        this.mView = mView;
    }

    public void setmModel(M mModel) {
        this.mModel = mModel;
    }

    public M getModel() {
        return mModel;
    }
}
